#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QtNetwork>
#include <QMessageBox>
#include <QtXml>
#ifdef QT_DEBUG
#include <QDebug>
#endif
#include <QTimer>
#include <QJsonDocument>

MainWindow::MainWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow),
    last_time(0), locked(false), running(false)
{
    ui->setupUi(this);

    readSettings();

    update_timer = new QTimer(this);
    connect(update_timer, SIGNAL(timeout()), this, SLOT(updateMessages()));

    manager = new QNetworkAccessManager(this);
    connect(manager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(replyFinished(QNetworkReply*)));

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::replyFinished(QNetworkReply *reply)
{
    if (reply->error() != QNetworkReply::NoError) {
        ui->comments->append("<div style=\"color: red\"><b>Connection problem, check your url!</b></div>");
    } else {
        QDomDocument d;
        d.setContent(reply);

        QDomNodeList nl = d.elementsByTagName("html_content");
        Q_ASSERT(nl.size() == 1);

        QDomNode content_node = nl.item(0).firstChild();
        Q_ASSERT(content_node.isCDATASection());

        QString json_raw = content_node.nodeValue();

        // parse json
        QJsonParseError error;
        QJsonDocument json_doc = QJsonDocument::fromJson(json_raw.toLatin1(), &error);
        Q_ASSERT(error.error == QJsonParseError::NoError);

        QVariantMap result = json_doc.toVariant().toMap();

        // TODO: handle result["poll_delay"].toInt();

#if 0
        QVariant deleted_comments = result["deleted_comments"];
        qDebug() << deleted_comments;
#endif

        int latestCommentTime = 0;

        QList<QVariant> raw_comments_list = result["comments"].toList();

        foreach (const QVariant &raw_comment, raw_comments_list) {
            QVariantMap comment_mapped = raw_comment.toMap();

            QString comment_id = comment_mapped["comment_id"].toString();
            if (lastMessages.contains(comment_id)) {
//                qDebug() << "skip" << comment_id;
                continue;
            }

            // TODO: handle comment_mapped["author_id"].toString();
            QString author_name = comment_mapped["author_name"].toString(),
                    author_url = comment_mapped["author_url"].toString(),
                    comment = comment_mapped["comment"].toString().trimmed();

//            qDebug() << comment_id << comment;

            comment.remove(QChar(ushort(65279))); // remove nbsp;
            comment.replace('&', "&amp;");
            comment.replace('"', "&quot;");
            comment.replace('<', "&lt;");
            comment.replace('>', "&gt;");
            comment.replace('\n', "<br>");

            int time_raw = comment_mapped["time_created"].toInt();

            if (time_raw > latestCommentTime) {
                latestCommentTime = time_raw;
            }

            // TODO: handle comment_mapped["is_deleted"].toBool();
            QDateTime time_created = QDateTime::fromTime_t(time_raw);

            QString comment_formatted = QString("<div style=\"margin-bottom: 5px\"><b>%1</b> <a href=\"http://youtube.com%2\">%3</a>: %4</div>")
                    .arg(time_created.toString("hh:mm:ss"), author_url, author_name, comment);
            ui->comments->append(comment_formatted);
        }

        if (!raw_comments_list.isEmpty()) {
//            qDebug() << "clear";
            lastMessages.clear();
        }

        last_time = qMax(last_time, latestCommentTime);

        foreach (const QVariant &raw_comment, raw_comments_list) {
            QVariantMap comment_mapped = raw_comment.toMap();

            int comment_time = comment_mapped["time_created"].toInt();
            if (comment_time == last_time) {
                QString comment_id = comment_mapped["comment_id"].toString();
                lastMessages.insert(comment_id);
//                qDebug() << "insert" << comment_id;

            }
        }
    }

    locked = false;
}

void MainWindow::on_update_clicked()
{
    if (!running) {
        QString url = ui->url->text();

        if (url.isEmpty()) {
            QMessageBox::critical(this, tr("Enter URL"),
                                  tr("Enter your livestream URL before pressing this button!"));
            return;
        }

        int pos = url.indexOf("?v=");
        if (pos == -1) {
            pos = url.indexOf("&v=");
        }

        if (pos == -1) {
            QMessageBox::critical(this, tr("Wrong URL"),
                                  tr("Adress should use format\n"
                                     "http://www.youtube.com/watch?v=..."));
            return;
        }

        int start_pos = pos + 3;
        int end_pos = url.indexOf("&", start_pos);
        int width = (end_pos == -1) ? -1 : (end_pos - start_pos);
        stream_id = url.mid(start_pos, width);

        updateMessages();

        ui->update->setIcon(QIcon(":/pause"));
        ui->url->setEnabled(false);
        running = true;
    } else {
        update_timer->stop();
        ui->update->setIcon(QIcon(":/play"));
        ui->url->setEnabled(true);
        running = false;
    }
}

void MainWindow::updateMessages()
{
    if (!locked) {
        locked = true;

        QString url = QString("http://www.youtube.com/live_comments?action_get_comments=1&video_id=%1&"
                              "lt=%2&format=json&nnc=%3&pd=%4&rc=1&dst=0&lch=0&ps=1&pvd=0&pct=0&scr=false")
                .arg(stream_id) // id
                .arg(last_time - 1) // lt -- last time // 1359820218
                .arg(71) // nnc ???
                .arg(30000); // pd - poll_delay, 30s
                // lch - this.p.offsetHeight //4431
                // pvd/pcd - getDuration/GetCurrentTime // 3105.108

        manager->get(QNetworkRequest(QUrl(url)));
    }

    int sec_update = ui->fastmode->isChecked() ? fast_speed : slow_speed;
    update_timer->start(sec_update * 1000);
}

void MainWindow::on_fastmode_toggled(bool checked)
{
    if (checked && running) {
        update_timer->start(0);
    }
}

void MainWindow::on_fixwindow_toggled(bool checked)
{
    Qt::WindowFlags flags = this->windowFlags();
    if (checked)
    {
        this->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
        this->show();
    }
    else
    {
        this->setWindowFlags(flags ^ (Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint));
        this->show();
    }
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    saveSettings();
    QWidget::closeEvent(event);
}

void MainWindow::readSettings()
{
    QSettings settings("LokiStudios", "Commentoshka");
    restoreGeometry(settings.value("geometry").toByteArray());
    ui->fastmode->setChecked(settings.value("fastmode", true).toBool());
    ui->fixwindow->setChecked(settings.value("fixwindow", true).toBool());

    slow_speed = settings.value("slow_speed", 30).toInt();
    fast_speed = settings.value("fast_speed", 1).toInt();

    ui->slowSpeed->setValue(slow_speed);
    ui->fastSpeed->setValue(fast_speed);
}

void MainWindow::saveSettings()
{
    QSettings settings("LokiStudios", "Commentoshka");
    settings.setValue("geometry", saveGeometry());
    settings.setValue("fastmode", ui->fastmode->isChecked());
    settings.setValue("fixwindow", ui->fixwindow->isChecked());

    slow_speed = ui->slowSpeed->value();
    fast_speed = ui->fastSpeed->value();

    settings.setValue("slow_speed", slow_speed);
    settings.setValue("fast_speed", fast_speed);
}

void MainWindow::on_settings_clicked()
{
    ui->stackedWidget->setCurrentIndex(1);
}

void MainWindow::on_saveSettings_clicked()
{
    saveSettings();
    ui->stackedWidget->setCurrentIndex(0);
}
